import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;


public class Ex2_5 {


	//LEADERBOARDCYCLOPEPTIDESEQUENCING(Spectrum, N)
	//Leaderboard ← {0-peptide}
	//LeaderPeptide ← 0-peptide
	//while Leaderboard is non-empty
	//    Leaderboard ← Expand(Leaderboard)
	//    for each Peptide in Leaderboard
	//        if Mass(Peptide) = ParentMass(Spectrum)
	//            if Score(Peptide, Spectrum) > Score(LeaderPeptide, Spectrum)
	//                LeaderPeptide ← Peptide
	//        else if Mass(Peptide) > ParentMass(Spectrum)
	//            remove Peptide from Leaderboard
	//    Leaderboard ← Cut(Leaderboard, Spectrum, N)
	// output LeaderPeptide

	private ArrayList<Integer> masses;
	private ArrayList<Integer> spectrum;
	private ArrayList<ArrayList<Integer>> leaderBoard;
	private ArrayList<Integer> leaderPeptide;
	private Integer n;
	private Integer parentM;
	private ArrayList<Integer> ZERO_PEPTIDE;	

	public Ex2_5() {		
		
		n = 200;
		masses = new ArrayList<Integer>();		
		leaderBoard = new ArrayList<ArrayList<Integer>>();
		spectrum = new ArrayList<Integer>();
		ZERO_PEPTIDE = new ArrayList<Integer>();
		leaderPeptide =  new ArrayList<Integer>();
		
		// input data
		loadSpectre("C:\\Users\\josemfer\\Downloads\\dataset_24_4.txt");
		loadMasses("C:\\Users\\josemfer\\Downloads\\integer_mass_table.txt");

		// initializing values
		ZERO_PEPTIDE.add(new Integer("0"));
		leaderBoard.add(ZERO_PEPTIDE);
		leaderPeptide = ZERO_PEPTIDE;
		parentM = getParentMass();
	}


	public void leadersequence() {		

		while (!leaderBoard.isEmpty()) {
			leaderBoard = expand(leaderBoard);					
			
			
			// get iterator
			Iterator<ArrayList<Integer>> it = leaderBoard.iterator();
			
			// for each Peptide in Leaderboard BEGIN
			while (it.hasNext()) {
				// get peptide
				ArrayList<Integer> peptide = it.next();		
				
				//if ( formatter(peptide).equals("156-71-113-114-131-156-113-101-129-128-128-114-128-103")) {
					//System.out.println("");
				//}					
				
				if (getMass(peptide).intValue() == 
							parentM.intValue()) {								
					if (getScore(peptide).intValue() > 
								getScore(leaderPeptide).intValue()) {
						leaderPeptide = peptide;
					}
				} else if (getMass(peptide).intValue() > parentM.intValue()  ) {
					
					//if ( formatter(peptide).equals("156-71-113-114-131-156-113-101-129-128-128-114-128-103")) {
					//	System.out.println("");
					//}
					
					
					it.remove();
				}
			} // for each Peptide in Leaderboard END
			cut();
		}
		System.out.println(formatter(leaderPeptide));
	}
	
	private String formatter(ArrayList<Integer> peptide) {	
		
		return peptide.toString().replaceAll("\\]", "").
					replaceAll("\\[", "").replaceAll(", ", "-");
	}
	
	

	// Cut(Leaderboard, Spectrum, N)
	private void cut() {
		
		ArrayList<ArrayList<Integer>> leaderBoardCopy = 
						new ArrayList<ArrayList<Integer>>(leaderBoard);
		ArrayList<ArrayList<Integer>> peptides = 
								new ArrayList<ArrayList<Integer>>();
		HashMap<ArrayList<Integer>, Integer> 
				hm = new HashMap<ArrayList<Integer>, Integer>();		
		for (ArrayList<Integer> peptide : leaderBoardCopy) {
			
			//if ( formatter(peptide).equals("156-71-113-114-131-156-113-101-129-128-128-114-128-103")) {
				//System.out.println("");
			//}
			
			Integer sc = getScore(peptide);			
			hm.put(peptide, sc);			
		}				
			
		ArrayList<Integer> values = new ArrayList<Integer>(hm.values());
		values = removeDuplicates(values);
		Collections.sort(values);
		Collections.reverse(values);		
		for (Integer val : values ) { // iterating scores		
			 if (peptides.size() >= n) {
	        	 this.leaderBoard = peptides;
	        	 return;
	         }
			 for (Entry<ArrayList<Integer>, Integer> entry : hm.entrySet()) {		       
				 if (val.intValue() == entry.getValue().intValue()   ) {
		             peptides.add(entry.getKey());		                        
		         }		        
		     }	
			
		} // iterating scores	
		
		this.leaderBoard = peptides;
   	 	return;
		
	}

	
	private ArrayList<Integer>removeDuplicates(ArrayList<Integer> aList) {		
		HashSet<Integer> listToSet = new HashSet<Integer>(aList);
		return new ArrayList<Integer>(listToSet);		
	}
	
	private Integer getScore(ArrayList<Integer> aPeptide) {		
		int counter = 0;
		// copy spectrum
		ArrayList<Integer> experimentalSpec = new ArrayList<Integer>(spectrum);
		//ArrayList<Integer> pepspec1 = getCyclospectrum(aPeptide);
		//ArrayList<Integer> pepspec2 = (ArrayList<Integer>) pepspec1.clone();
		
		for (Integer mass : getCyclospectrum(aPeptide)) {
			if (experimentalSpec.contains(mass)) {
				counter++;
				experimentalSpec.remove(mass);
			}
		}	
			
		
		
		return Integer.valueOf(counter);
	}
	
	
	public ArrayList<Integer> getCyclospectrum(ArrayList<Integer> peptide) {
		ArrayList<Integer> sp = new ArrayList<Integer>();	
		//Integer k = new Integer("0");
		//sp.add(k);	
		ArrayList<Integer> cyclop = new ArrayList<Integer>();
		cyclop.addAll(peptide);
		cyclop.addAll(peptide);		
		for (int i=1;i<peptide.size()+1;i++) { // i-mer			
			for (int j=0;j<peptide.size();j++) {				
				if (i==1) {
					sp.add(peptide.get(j));
				} else if (i==peptide.size() && j > 0) {
					break;
				} else {				
					sp.add(sp.get( (i-2)*peptide.size() + j) + cyclop.get(i-1+j));
				}			
			} // j		
		}		
		//Collections.sort(sp);
		return sp;	
	}

	
	private Integer getParentMass() {		
		return Collections.max(spectrum);
	}


	private Integer getMass(ArrayList<Integer> peptide) {
		int sum = 0;
		for (Integer m : peptide) {
			sum += m.intValue();
		}
		
		return Integer.valueOf(sum);
	}

	

	private ArrayList<ArrayList<Integer>> expand(
			ArrayList<ArrayList<Integer>> oldList) {
		ArrayList<ArrayList<Integer>> newList = new ArrayList<ArrayList<Integer>>();
		for (ArrayList<Integer> l : oldList) {
			for (Integer m : this.masses) {
				ArrayList<Integer> pep = new ArrayList<Integer>();
				if (oldList.size() > 1) {
					pep.addAll(l);
				}
				
				//if ( formatter(pep).equals("156-71-113-114-131-156-113-101-129-128-128-114-128")) {
				//	System.out.println("");
				//}
				
				pep.add(m);
				newList.add(pep);
				
				//if ( formatter(pep).equals("156-71-113-114-131-156-113-101-129-128-128-114-128-103")) {
					//System.out.println("");
				//}
				
				
			}
		}	
		return newList;		
	}


	/*
	public ArrayList<Integer> getLinealSpectrum(ArrayList<Integer> peptide) {
		ArrayList<Integer> sp = new ArrayList<Integer>();    
		sp.add(0);  
		ArrayList<Integer> cyclop = new ArrayList<Integer>();
		cyclop.addAll(peptide);
		//cyclop.addAll(peptide);          
		for (int i=1;i<peptide.size()+1;i++) { // i-mer
			for (int j=0;j<peptide.size()-i+1;j++) {
				int sum = 0;                     
				// sum elements in sub list
				for (int s : cyclop.subList(j, j+i)) {
					sum += s;
				}                         
				sp.add(sum);
				if (i == peptide.size()) {
					break;                           
				}
			}           
		}           
		//Collections.sort(sp);
		return sp;  
	} */
	
	
	

	private void loadSpectre(String file) {		
		try {
			String inputFile = KmerCounter.readFile(file);
			for (String s : inputFile.split("\\s+")) {
				spectrum.add(new Integer(s));
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}

	private void loadMasses(String file) 
	{		
		try {
			HashMap<String, String> hm = new HashMap<String, String>();
			BufferedReader reader = new BufferedReader( new FileReader (file));
			String         line = null;				
			while( ( line = reader.readLine() ) != null ) {			
				String[] l = line.split("\\s+");
				if (!masses.contains(l[1])) {
					masses.add(new Integer(l[1])  );
				}				
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 			
	}	




	public static void main(String[] args) {
		System.out.println(new Date());
		Ex2_5 exer = new Ex2_5();
		exer.leadersequence();
		
				
		/* ArrayList<Integer> test = new ArrayList<Integer>();
		test.add(1);
		test.add(2);
		test.add(3);
		test.add(4);
		test.add(5); 		
		ArrayList<Integer> sp = exer.getCyclospectrum(test);
		System.out.println(sp); */
		
		System.out.println(new Date());
	}	


}
